﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MovieRental.DataInterfaces;
using MovieRental.Entities;
using MovieRental.BuisnessComponents.Base;
using MovieRental.BuisnessComponents.Helpers;
using MovieRental.BuisnessComponents.Exceptions;

namespace MovieRental.BuisnessComponents
{
    public class CartDiscountComponent : BaseSetComponent<CartDiscountInfo, Guid, ICartDiscountRepository>
    {
        public CartDiscountComponent(ICartDiscountRepository repository)
            : base(repository)
        {
        }

        protected override bool Equals(CartDiscountInfo obj1, CartDiscountInfo obj2)
        {
            return (obj1.QuantityCondition == obj2.QuantityCondition);
        }

        public override void Verify(CartDiscountInfo obj)
        {
            base.Verify(obj);
            if (obj.QuantityCondition < 0)
                throw new FieldValueRangeException<int>(obj, "QuantityCondition", 0, int.MaxValue);
            ValueBound<double> bounds = GetValueBoundsForCondition(obj.QuantityCondition);
            if (!bounds.IsInBounds(obj.Value))
                throw new FieldValueRangeException<double>(obj, "Value", bounds.Lower, bounds.Upper);
        }

        public override IEnumerable<CartDiscountInfo> GetAll()
        {
            return base.GetAll().OrderBy(x => x.QuantityCondition);
        }

        public CartDiscountInfo AddDiscountRule(int quantity, double value)
        {
            var discount = new CartDiscountInfo();
            discount.QuantityCondition = quantity;
            discount.Value = value;
            try
            {
                AddOrUpdate(discount);
            }
            catch (ItemDuplicateException<Guid> ex)
            {
                var duplicate = (CartDiscountInfo)ex.DuplicateObject;
                duplicate.Value = value;
                AddOrUpdate(duplicate);
            }
            return discount;
        }

        public ValueBound<double> GetValueBoundsForCondition(int quantity)
        {
            double lower, upper;
            var lowerDiscounts = Repository.LoadAll().Where(x => x.QuantityCondition < quantity).OrderBy(x => x.QuantityCondition);
            if (!lowerDiscounts.Any())
                lower = 0;
            else
                lower = lowerDiscounts.Last().Value;
            var upperDiscounts = Repository.LoadAll().Where(x => x.QuantityCondition > quantity).OrderBy(x => x.QuantityCondition);
            if (!upperDiscounts.Any())
                upper = 100.0;
            else
                upper = upperDiscounts.First().Value;
            return new ValueBound<double>(lower, upper);
        }

        public CartDiscountInfo GetAvailableCartDiscount(int quantity)
        {
            return Repository.LoadAll().Where(x => x.QuantityCondition <= quantity).OrderBy(x => x.QuantityCondition).LastOrDefault();
        }

        public double GetAvailableCartDiscountValue(int quantity)
        {
            var cartDiscount = GetAvailableCartDiscount(quantity);
            if (cartDiscount == null)
                return 0;
            else
                return cartDiscount.Value;
        }


        
    }
}
